<?

	require_once PKG_DIR.'/SmRoot/ClassInterfaces.php';
	
	final class Package_SmRoot0v0r01 extends _smuoiPackage implements Package_SmRoot{
		
		protected $primary_grps = array();
		
		private $session;
		
		function root_id(){
			return $this->apply_key('users', 500);	
		}
		
		function root_grp(){
			return $this->apply_key('groups', 500);	
		}
		
		function open_session($uname, $sha1, $salt){
			if(PUBLIC_DOMAIN) return $this->open_error("403 no authentication permitted from public domain", E_USER_ERROR);
			$a = explode('/', strtolower($uname));
			// No time for syntax breakers...
			if(($do_sudo = isset($a[1]))&&($a[1] != 'sudo')) return false;
			// 
			$uname = $a[0];
			$t = $this->table('users');
			if(!$u = $this->al()->select('*', $t, array('name'=>$uname))) return false;
			$usr = $this->db->register($u[0], $t, 1, 1);
			// Check bad attempts at sudo-ing
			if($do_sudo && !($usr instanceof SmRoot_Sudoer)) return $this->open_error("401 $usr->name is not a sudoer!");
			// check user has access to domain
			if(!PUBLIC_DOMAIN && !sm_cwdom()->will_permit($usr)) return $this->open_error("403 $usr->name has no access to ".sm_getcwdom());
			// Now check the password
			if(!$session = $usr->pass_check($sha1, $salt, $do_sudo)) return $this->open_error("$usr->name failed password on ".sm_getcwdom());
			// new session? register cookie output method
			if(!$this->session) $this->register_kookyput();
			// else if switched user, destroy old session
			elseif($this->session !== $session) $this->session->destroy();
			$this->session = $session;
			$session->commit();
			return $session;
		}
		
		private function open_error($e, $L=E_USER_NOTICE){
			trigger_error($e, $L);
			return false;
		}
		
		function restore_session(){
			$key = (PUBLIC_DOMAIN || DOUPLOAD) ? 'pubkey' : 'kooky';
			if(!$val = cookie($key)) return false;
			$t = $this->table('sessions');
			if(!$data = $this->al()->select('*', $t, 
				array(
					  $key => $val, 
					  'ip' => $_SERVER['REMOTE_ADDR']
				)
			)) return $this->delete_cookie($key);
			$session = $this->db->register($data[0], $t, 1, 1);
			if(!$session->ok()) return $this->delete_cookie($key);
			$this->register_kookyput();
			$this->session = $session;
			return $session;
		}
		
		function close_session(){
			if($this->session || $this->restore_session()) $this->session->destroy();
			$this->delete_cookie('kooky');
			$this->delete_cookie('pubkey');
		}
		
		// don't make us run restore_session second time with invalid cookie
		// returns false for convenience of restore_session conditions
		private function delete_cookie($key){
			setcookie($key, '', 1, '/', SERVER_NAME);
			return false;
		}
		
		function session(){
			return $this->session;	
		}
		
		function usr(){
			if($this->session) return $this->session->usr();	
		}
		
		function register_kookyput(){
			if(!PUBLIC_DOMAIN) sn()->register_event_func('headers', array($this, 'put_kooky'));
		}

		function put_kooky(){
			if(!$ses = $this->session) return;
			setcookie('kooky', $ses->kooky(), $ses->expires, '/', SERVER_NAME);	
		}
		
		// returns primary group of instantiated user
		function primary_of($u){
			static $primaries = array();
			if(!$u instanceof SmRoot_User) return false;
			if(isset($primaries[$u->id])) return $primaries[$u->id];
			if(!$grp = $this->al()->select('*', $this->table('groups'), array('nam'=>':'.$u->id))) return $this->newGroup(':'.$u->id);
			$grp = $primaries[$u->id] = $this->db->register($grp[0]);
			return $grp;
		}
		
		// initDomain is called by DesktopDomain
		// it allows for new domain creation by simply creating an ini file
		function initDomain($id, $mkname=false){
			$dbid = $this->apply_key('domains', $id);
			if($dom = $this->db->get($dbid)) return $dom;
			if(!$mkname) return false;
			return $this->newDomain($id, $mkname);
		}
		
		function new_id($k){
			$t = $this->db->tableFromKey($k);
			if($t == 'sessions') return parent::new_id($k);
			$n = $this->al()->count_rows($t);
			do{
				$id = str_pad(base_convert($n, 10, 36), 3, 0, STR_PAD_LEFT);
				$n++;
			}while($this->al()->exists($t, array('id'=>$k.$id)));
			return $k.$id;
		}
		
####	THESE DON'T BELONG HERE
		
		function check_dom_id($dom_id){
			$dom_id = preg_replace('/[^a-z0-9]/', '', strtolower($dom_id));
			$id = $this->apply_key('domains', $dom_id);
			return ((strlen($dom_id) == 8)&&(!$this->al()->exists($this->table('domains'), array('id'=>$id)))) ? $id : false;
		}
		
		function detect_domain_name_clash($name, $id){
			$dbid = $this->apply_key('domains', $id);	
			return $this->al()->exists($this->table('domains'), array('name'=>$name, '!id'=>$dbid));
		}
		
		private function new_name_on($t, $n, $f='name'){
			$n = preg_replace('/[^A-Za-z]/', '', $n);
			if(!$n) $n = substr($t, 0, -1);
			$name = $n;
			$i = 0;
			$t = $this->table($t);
			while($this->al()->exists($t, array($f=>$name))) $name = $n.$i++;
			return $name;
		}
		
		function newUser($name='NewUser'){
			$id = $this->new_id_on('users');
			$name = $this->new_name_on('users', $name);
			$o = new obj(array(
				'id'=>$id,
				'name'=>$name,
				'home'=>DOM_ID,
				'email'=>$name.'@'.DOM_NAME,
				'password'=>rand_string(40)
			));
			return $this->commitNew($o, 'User');
		}
		
		function newGroup($nam='NewGroup'){
			$id = $this->new_id_on('groups');
			if(substr($nam, 0, 1) != ':') $nam = $this->new_name_on('groups', $nam, 'nam');
			$o = new obj(array(
				'id'=>$id,
				'nam'=>$nam
			));
			return $this->commitNew($o, 'group');
		}
	
		private function newDomain($dom_id, $name='NewDomain'){
			$t = $this->table('domains');
			if(!$id = $this->check_dom_id($dom_id)) return false;
			$name = $this->new_name_on('domains', HostInterface::domname($name));
			$o = new obj(array(
				'id'=>$id,
				'name'=>$name,
				'own'=>$this->root_id(),
				'grp'=>$this->root_grp()
			));
			return $this->commitNew($o, 'Domain');
		}
		
		private function commitNew($o, $cname){
			require_once $this->path_to_dataclass($cname);
			$class = $this->apply_namespace($cname);
			$n = new $class(false, $this, $o);
			($cname != 'Domain') ? $n->commit(1) : $n->dom_commit(1);
			return $n;
		}
	}

?>
